function convert(input) { alert('Error. Contact us if this keeps happening.'); document.getElementById('modal-contact').classList.add('show'); } window.ctMaxUploadFiles = 1; var _atState = { buffer: null, fileName: 'audio', start: 0, end: 0, duration: 0 }; function _atFormatTime(t) { if (!isFinite(t) || t < 0) t = 0; var m = Math.floor(t / 60); var s = (t - m * 60); var ss = s.toFixed(2); if (s < 10) ss = '0' + ss; return m + ':' + ss; } function _atDrawWave(buffer) { var canvas = document.getElementById('at-waveform'); if (!canvas || !buffer) return; var dpr = window.devicePixelRatio || 1; var w = canvas.clientWidth || canvas.parentElement.clientWidth || 600; canvas.width = Math.floor(w * dpr); canvas.style.width = w + 'px'; canvas.height = 96 * dpr; canvas.style.height = '96px'; var ctx = canvas.getContext('2d'); ctx.scale(dpr, dpr); ctx.clearRect(0, 0, w, 96); ctx.fillStyle = '#f7fbf8'; ctx.fillRect(0, 0, w, 96); var ch = buffer.getChannelData(0); var samplesPerBar = Math.max(1, Math.floor(ch.length / w)); ctx.fillStyle = '#2d7a2d'; for (var x = 0; x < w; x++) { var min = 1, max = -1; var s = x * samplesPerBar; var e = Math.min(ch.length, s + samplesPerBar); for (var i = s; i < e; i++) { var v = ch[i]; if (v < min) min = v; if (v > max) max = v; } var y1 = (1 - max) * 48; var y2 = (1 - min) * 48; ctx.fillRect(x, y1, 1, Math.max(1, y2 - y1)); } } function _atBindHandles() { var track = document.getElementById('at-track'); var h1 = document.getElementById('at-h1'); var h2 = document.getElementById('at-h2'); if (!track || track._atBound) return; track._atBound = true; function startDrag(handle, e) { e.preventDefault(); var rect = track.getBoundingClientRect(); function move(ev) { var p = (ev.touches ? ev.touches[0].clientX : ev.clientX) - rect.left; var pct = Math.max(0, Math.min(100, (p / rect.width) * 100)); handle.style.left = pct + '%'; _atUpdateFromHandles(); } function up() { document.removeEventListener('pointermove', move); document.removeEventListener('pointerup', up); } document.addEventListener('pointermove', move); document.addEventListener('pointerup', up); } h1.addEventListener('pointerdown', function(e){ startDrag(h1, e); }); h2.addEventListener('pointerdown', function(e){ startDrag(h2, e); }); } function _atUpdateFromHandles() { var h1pct = parseFloat(document.getElementById('at-h1').style.left) || 0; var h2pct = parseFloat(document.getElementById('at-h2').style.left) || 100; var lo = Math.min(h1pct, h2pct), hi = Math.max(h1pct, h2pct); var dur = _atState.duration; _atState.start = (lo / 100) * dur; _atState.end = (hi / 100) * dur; var fill = document.getElementById('at-fill'); if (fill) { fill.style.left = lo + '%'; fill.style.width = (hi - lo) + '%'; } document.getElementById('at-start').textContent = _atFormatTime(_atState.start); document.getElementById('at-end').textContent = _atFormatTime(_atState.end); document.getElementById('at-duration').textContent = '/ ' + _atFormatTime(_atState.end - _atState.start); } function processFile(blob, fileName) { _atState.fileName = fileName || 'audio'; $('#file-drop-zone').addClass('collapsedDropZone'); (function(){ var $b=$('#file-drop-zone .upload-file-button'); var l=$b.data('change-label'); if(l) $b.text(l); })(); var ws = document.getElementById('at-workspace'); if (ws) ws.style.display = 'block'; var audio = document.getElementById('at-audio'); if (audio) audio.src = URL.createObjectURL(blob); var reader = new FileReader(); reader.onload = function(e) { var AC = window.AudioContext || window.webkitAudioContext; if (!AC) { alert('Web Audio is not supported in this browser.'); return; } var ac = new AC(); ac.decodeAudioData(e.target.result.slice(0), function(buf) { _atState.buffer = buf; _atState.duration = buf.duration; document.getElementById('at-h1').style.left = '0%'; document.getElementById('at-h2').style.left = '100%'; _atUpdateFromHandles(); _atDrawWave(buf); _atBindHandles(); }, function(err) { alert('Could not decode this audio file. Try MP3, WAV, M4A, OGG, or FLAC.'); }); }; reader.readAsArrayBuffer(blob); } function _atSliceBuffer() { var buf = _atState.buffer; if (!buf) return null; var sr = buf.sampleRate; var startSample = Math.max(0, Math.floor(_atState.start * sr)); var endSample = Math.min(buf.length, Math.floor(_atState.end * sr)); if (endSample - startSample < 32) return null; var ch = buf.numberOfChannels; var newBuf = new AudioBuffer({ length: endSample - startSample, sampleRate: sr, numberOfChannels: ch }); for (var c = 0; c < ch; c++) { var src = buf.getChannelData(c); var dst = newBuf.getChannelData(c); for (var i = startSample, j = 0; i < endSample; i++, j++) dst[j] = src[i]; } return newBuf; } function _atEncodeWav(buffer) { var ch = buffer.numberOfChannels; var sr = buffer.sampleRate; var samples = buffer.length * ch; var bytesPerSample = 2; var size = 44 + samples * bytesPerSample; var ab = new ArrayBuffer(size); var view = new DataView(ab); var ws = function(o, s) { for (var i = 0; i < s.length; i++) view.setUint8(o + i, s.charCodeAt(i)); }; ws(0, 'RIFF'); view.setUint32(4, size - 8, true); ws(8, 'WAVE'); ws(12, 'fmt '); view.setUint32(16, 16, true); view.setUint16(20, 1, true); view.setUint16(22, ch, true); view.setUint32(24, sr, true); view.setUint32(28, sr * ch * bytesPerSample, true); view.setUint16(32, ch * bytesPerSample, true); view.setUint16(34, 16, true); ws(36, 'data'); view.setUint32(40, samples * bytesPerSample, true); var offset = 44; var data = []; for (var c = 0; c < ch; c++) data.push(buffer.getChannelData(c)); for (var i = 0; i < buffer.length; i++) { for (var c2 = 0; c2 < ch; c2++) { var s = Math.max(-1, Math.min(1, data[c2][i])); view.setInt16(offset, s < 0 ? s * 32768 : s * 32767, true); offset += 2; } } return new Blob([ab], { type: 'audio/wav' }); } function _atEncodeMp3(buffer, bitrate) { return loadScriptPromise('https://cdn.jsdelivr.net/npm/lamejs@1.2.1/lame.min.js').then(function() { if (typeof lamejs === 'undefined') throw new Error('MP3 encoder failed to load'); var ch = Math.min(2, buffer.numberOfChannels); var sr = buffer.sampleRate; var mp3enc = new lamejs.Mp3Encoder(ch, sr, bitrate); var left = buffer.getChannelData(0); var right = ch > 1 ? buffer.getChannelData(1) : null; var samples = buffer.length; var leftI16 = new Int16Array(samples); var rightI16 = right ? new Int16Array(samples) : null; for (var i = 0; i < samples; i++) { var l = Math.max(-1, Math.min(1, left[i])); leftI16[i] = l < 0 ? l * 32768 : l * 32767; if (rightI16) { var r = Math.max(-1, Math.min(1, right[i])); rightI16[i] = r < 0 ? r * 32768 : r * 32767; } } var blockSize = 1152; var chunks = []; for (var i = 0; i < samples; i += blockSize) { var lChunk = leftI16.subarray(i, i + blockSize); var enc; if (rightI16) { var rChunk = rightI16.subarray(i, i + blockSize); enc = mp3enc.encodeBuffer(lChunk, rChunk); } else { enc = mp3enc.encodeBuffer(lChunk); } if (enc.length > 0) chunks.push(new Int8Array(enc)); } var end = mp3enc.flush(); if (end.length > 0) chunks.push(new Int8Array(end)); return new Blob(chunks, { type: 'audio/mpeg' }); }); } function _atApply() { if (!_atState.buffer) { alert('Drop an audio file first.'); return; } var sliced = _atSliceBuffer(); if (!sliced) { alert('Pick a longer range to trim.'); return; } var format = document.getElementById('at-format').value; var status = document.getElementById('at-status'); var btn = document.getElementById('at-apply'); if (btn) btn.disabled = true; var base = (_atState.fileName || 'audio').replace(/\.[^.]+$/, ''); if (format === 'wav') { if (status) status.textContent = 'Encoding WAV...'; var blob = _atEncodeWav(sliced); add_file_output(URL.createObjectURL(blob), base + '-trimmed.wav'); if (status) status.textContent = 'Done.'; if (btn) btn.disabled = false; } else { var bitrate = parseInt(document.getElementById('at-bitrate').value, 10) || 192; if (status) status.textContent = 'Encoding MP3...'; _atEncodeMp3(sliced, bitrate).then(function(blob) { add_file_output(URL.createObjectURL(blob), base + '-trimmed.mp3'); if (status) status.textContent = 'Done.'; if (btn) btn.disabled = false; }).catch(function(err) { if (status) status.textContent = ''; if (btn) btn.disabled = false; alert('Could not encode MP3: ' + (err && err.message || err)); }); } } function _atInit() { var format = document.getElementById('at-format'); if (format) format.addEventListener('change', function() { var bw = document.getElementById('at-bitrate-wrap'); if (bw) bw.style.display = format.value === 'mp3' ? '' : 'none'; }); var apply = document.getElementById('at-apply'); if (apply) apply.addEventListener('click', _atApply); window.addEventListener('resize', function() { if (_atState.buffer) _atDrawWave(_atState.buffer); }); } document.addEventListener('DOMContentLoaded', _atInit); if (document.readyState !== 'loading') _atInit(); var _loadedScripts = {}; function loadScriptPromise(url) { if (_loadedScripts[url]) return _loadedScripts[url]; _loadedScripts[url] = new Promise(function (resolve, reject) { var s = document.createElement('script'); s.src = url; s.onload = resolve; s.onerror = reject; document.head.appendChild(s); }); return _loadedScripts[url]; } function replaceAll(find, replace, str) { return str.replace(new RegExp(find, 'g'), replace); } function beautify(str) { var result = ''; var length = str.length; var i = 0; var braceCountLeft = 0; var braceCountRight = 0; var withinQuotes = false; while (i < length) { var c = str[i]; if (c == '"' && (i == 0 || c[i - 1] != '\\')) { // non-escaped quotes withinQuotes = !withinQuotes; } if (!withinQuotes && (c == '}' || c == '{' || c == ',')) { console.log('Start####' + result); // look back and remove carriage returns and whitespace that are already there var resultIndex = result.length - 1; while (resultIndex >= 0 && (result[resultIndex] == ' ' || result[resultIndex] == '\r' || result[resultIndex] == '\n' || result[resultIndex] == '\t')) { resultIndex = resultIndex - 1; result = result.substr(0, resultIndex + 1); console.log('char ' + result[resultIndex] + '-----' + result + 'zzz ' + result.length + ' ' + resultIndex); } if (c == '{') { braceCountLeft++; result += c + '\r' + GetTabs(braceCountLeft - braceCountRight); } else if (c == '}') { braceCountRight++; // precede with carriage return result += '\r' + GetTabs(braceCountLeft - braceCountRight) + c; } else if (c == ',') { result += c + '\r' + GetTabs(braceCountLeft - braceCountRight); } var nextChar = ''; // advance through whitespace and remove carriage returns that are already there while (i < length && (str[i + 1] == ' ' || str[i + 1] == '\r' || str[i + 1] == '\n' || str[i + 1] == '\t')) { i++; } } else { result += str[i]; } i++; } return result; } function GetTabs(count) { var result = ''; for (var i = 0; i < count; i++) { result += ' '; } return result; }